﻿using System;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace IceDog.SmallProject.MonkeyCode
{
    class Program
    {
        static void Main(string[] args)
        {
            Override(() => Add(default, default), () => AddMore10(default, default));
            Console.WriteLine($"Add(1, 1) : {Add(1, 1)}");
            Console.ReadLine();
        }
        public static int Add(int x, int y) => x + y;
        public static int AddMore10(int x, int y) => x + y + 10;
        public static void Override(Expression<Action> originalCall, Expression<Action> targetCall)
        {
            var originalMethod = ((MethodCallExpression)originalCall.Body).Method;
            var targetMethod = ((MethodCallExpression)targetCall.Body).Method;

            RuntimeHelpers.PrepareMethod(originalMethod.MethodHandle);
            RuntimeHelpers.PrepareMethod(targetMethod.MethodHandle);

            var sourceAddress = originalMethod.MethodHandle.GetFunctionPointer();
            var targetAddress = (long)targetMethod.MethodHandle.GetFunctionPointer();

            int offset = (int)(targetAddress - (long)sourceAddress - 4 - 1);

            byte[] instruction = {
                0xE9, // JUMP
                (byte)(offset & 0xFF),
                (byte)((offset >> 8) & 0xFF),
                (byte)((offset >> 16) & 0xFF),
                (byte)((offset >> 24) & 0xFF)
            };

            Marshal.Copy(instruction, 0, sourceAddress, instruction.Length);
        }
    }
}
